package push

import (
	"gitee.com/yxd1990/golang-common/myType"
	"gitee.com/yxd1990/golang-common/utils"
	"encoding/json"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/httplib"
	"github.com/astaxie/beego/logs"
	"strconv"
	"sync"
	"time"
)

var appId string
var appSecret string
var appKey string
var masterSecret string
var lock4PushToken sync.Mutex
var authToken string
var authTokenExpireTime int64

type AuthTokenResult struct {
	Result     string `json:"result"`
	AuthToken  string `json:"auth_token"`
	Desc       string `json:"desc"`
	ExpireTime string `json:"expire_time"`
}
type StyleType int8

const (
	SystemStyle StyleType = iota
	SimpleStyle     // 个推样式
	BannerType  = 4 //纯图样式(背景图样式)
	ExpandStyle = 6 //展开通知样式
)

type StyleInfo struct {
	Type        StyleType `json:"type"`         // 固定为0
	Text        string    `json:"text"`         // 通知内容
	Title       string    `json:"title"`        // 通知标题
	Logo        string    `json:"logo"`         // 通知的图标名称，包含后缀名（需要在客户端开发时嵌入），如“push.png”
	IsRing      bool      `json:"is_ring"`      // 收到通知是否响铃：true响铃，false不响铃。默认响铃
	IsVibrate   bool      `json:"is_vibrate"`   // 收到通知是否振动：true振动，false不振动。默认振动
	IsClearable bool      `json:"is_clearable"` // 通知是否可清除： true可清除，false不可清除。默认可清除
	IsFloat     bool      `json:"is_float"`
	Logourl     string    `json:"logourl"`    // 通知图标URL地址
	BannerUrl   string    `json:"banner_url"` // 通过url方式指定动态banner图片作为通知背景图
	BigStyle    string    `json:"big_style"`  //	通知展示样式,枚举值包括 1,2,3
	/**
	big_style	必传属性	展开样式说明
	1	big_image_url	通知展示大图样式，参数是大图的URL地址
	2	big_text	通知展示文本+长文本样式，参数是长文本
	3	big_image_url,banner_url	通知展示大图+小图样式，参数是大图URL和小图URL
	*/
	BigImageUrl string `json:"big_image_url"` // 通知大图URL地址
	BigText     string `json:"big_text"`      // 通知展示文本+长文本样式，参数是长文本
}
type NotificationInfo struct {
	TransmissionType    bool      `json:"transmission_type"`
	TransmissionContent string    `json:"transmission_content"`
	DurationBegin       string    `json:"duration_begin"`
	DurationEnd         string    `json:"duration_end"`
	Style               StyleInfo `json:"style"`
}
type TransmissionInfo NotificationInfo
type MessageInfo struct {
	Appkey            string `json:"appkey"`              //注册应用时生成的appkey
	IsOffline         bool   `json:"is_offline"`          // 是否离线推送
	OfflineExpireTime int    `json:"offline_expire_time"` // 消息离线存储有效期，单位：ms
	PushNetworkType   int    `json:"push_network_type"`   //选择推送消息使用网络类型，0：不限制，1：wifi
	Msgtype           string `json:"msgtype"`             // 消息应用类型，可选项：notification、link、notypopload、transmission
}
type AlertInfo struct {
	Title string `json:"title"`
	Body  string `json:"body"`
}
type ApsInfo struct {
	AutoBadge        string    `json:"autoBadge"`
	ContentAvailable int       `json:"content_available"`
	Alert            AlertInfo `json:"alert"`
}
type PushInfoStruct struct {
	Aps     ApsInfo `json:"aps"`
	Payload string  `json:"payload"`
}
type NotypoploadInfo struct {
	Style       StyleInfo `json:"style"`
	Notytitle   string    `json:"notytitle"`
	Notycontent string    `json:"notycontent"`
	Notyicon    string    `json:"notyicon"`
	Poptitle    string    `json:"poptitle"`
	Popcontent  string    `json:"popcontent"`
	Popimage    string    `json:"popimage"`
	Popbutton1  string    `json:"popbutton1"`
	Popbutton2  string    `json:"popbutton2"`
}
type PushSingleRequest struct {
	Message MessageInfo `json:"message"` // 消息内容
	/**
	消息应用模板，见详情
	四种类型选其一
	该属性与message下面的msgtype一致
	*/
	Notification *NotificationInfo `json:"notification"`
	Transmission *TransmissionInfo `json:"transmission"`
	Notypopload  *NotypoploadInfo  `json:"notypopload"`
	PushInfo     *PushInfoStruct   `json:"push_info"` // json串，当手机为ios，并且为离线的时候
	Cid          string            `json:"cid"`       // 与alias二选一
	Requestid    string            `json:"requestid"` // 请求唯一标识
	Alias        string            `json:"alias"`     //与cid二选一
}

/**

push.AppID = XTwSbQ1Pml6rswFfZb8VR6
push.AppSecret = bJyJ1Z2hUt5Dox6vbJvTG5
push.AppKey = 4rYCcguyQN9gLwviGAjFc9
push.MasterSecret = JMC3kS7uRa6NoQ7EiYbte4

*/

func init() {
	/*if appId = beego.AppConfig.DefaultString("push.AppID", "dZl3k2E6NJ87knetphODF"); appId == "" {
		logs.Error("push.AppID can not be empty")
	}
	if appSecret = beego.AppConfig.DefaultString("push.AppSecret", "jtbMnsoRG16JcePGXhEtR5"); appSecret == "" {
		logs.Error("push.AppSecret can not be empty")
	}
	if appKey = beego.AppConfig.DefaultString("push.AppKey", "4kVJIJK8Cj9KuPKo4KX56A"); appKey == "" {
		logs.Error("push.AppKey can not be empty")
	}
	if masterSecret = beego.AppConfig.DefaultString("push.MasterSecret", "ZJA8ePJDNP8zWVD6lwMDx2"); masterSecret == "" {
		logs.Error("push.MasterSecret can not be empty")
	}*/
	if appId = beego.AppConfig.DefaultString("push.AppID", "XTwSbQ1Pml6rswFfZb8VR6"); appId == "" {
		logs.Error("push.AppID can not be empty")
	}
	if appSecret = beego.AppConfig.DefaultString("push.AppSecret", "bJyJ1Z2hUt5Dox6vbJvTG5"); appSecret == "" {
		logs.Error("push.AppSecret can not be empty")
	}
	if appKey = beego.AppConfig.DefaultString("push.AppKey", "4rYCcguyQN9gLwviGAjFc9"); appKey == "" {
		logs.Error("push.AppKey can not be empty")
	}
	if masterSecret = beego.AppConfig.DefaultString("push.MasterSecret", "JMC3kS7uRa6NoQ7EiYbte4"); masterSecret == "" {
		logs.Error("push.MasterSecret can not be empty")
	}
}

func GetAuthToken() (token string, err error) {
	if authToken != "" && authTokenExpireTime > myType.UnixSeconds() {
		return authToken, nil
	}
	lock4PushToken.Lock()
	if authToken != "" && authTokenExpireTime > myType.UnixSeconds() {
		return authToken, nil
	}
	url := fmt.Sprintf("https://restapi.getui.com/v1/%s/auth_sign", appId)
	req := httplib.Post(url)
	timestamp := time.Now().UnixNano() / int64(time.Millisecond)
	params := make(map[string]string)
	params["sign"] = utils.GetSha256Value(fmt.Sprintf("%s%d%s", appKey, timestamp, masterSecret))
	params["timestamp"] = fmt.Sprintf("%d", timestamp)
	params["appkey"] = appKey
	_, err = req.JSONBody(params)
	if err == nil {
		result := &AuthTokenResult{}
		var data []byte
		data, err = req.Bytes()
		if err == nil {
			logs.Info("getAuthToken response : %s", string(data))
			err = json.Unmarshal(data, result)
			if err == nil {
				authToken = result.AuthToken
				authTokenExpireTime, err = strconv.ParseInt(result.ExpireTime, 10, 64)
				if err == nil {
					token = authToken
				}
			}
		}
	}
	lock4PushToken.Unlock()
	return
}

type PushSingleResult struct {
	Result string `json:"result"` // 	ok 鉴权成功，
	Taskid string `json:"taskid"` // 任务编号
	Desc   string `json:"desc"`   // 错误信息描述
	/**
	推送结果
	successed_offline 离线下发
	successed_online 在线下发
	successed_ignore 非活跃用户不下发
	*/
	Status string `json:"status"` //
}

func PushSingle(request *PushSingleRequest) (result *PushSingleResult, err error) {
	request.Message.Appkey = appKey
	url := fmt.Sprintf("https://restapi.getui.com/v1/%s/push_single", appId)
	req := httplib.Post(url)
	var token string
	token, err = GetAuthToken()
	if err != nil {
		return
	}
	req.Header("authtoken", token)
	_, err = req.JSONBody(request)
	if err == nil {
		result := &PushSingleResult{}
		var data []byte
		req.Debug(true)
		logs.Info("push_single request :%s", string(req.DumpRequest()))
		data, err = req.Bytes()
		if err == nil {
			logs.Info("push_single to %s response : %s", request.Cid, string(data))
			err = json.Unmarshal(data, result)
		} else {
			logs.Error("push_single error:%s", request.Cid, err)
		}
	}
	return
}

func PushSingleMessage(cid string, title string, content string, payload string) (result *PushSingleResult, err error) {
	if cid == "" {
		return
	}
	data := &PushSingleRequest{}
	data.Message.IsOffline = true
	data.Message.OfflineExpireTime = 10000000 // 单位：ms
	data.Message.PushNetworkType = 0
	data.Message.Msgtype = "notification"
	data.Notification = &NotificationInfo{}
	data.Notification.Style.Type = SimpleStyle
	data.Notification.Style.Text = content
	data.Notification.Style.Title = title
	data.Notification.Style.IsRing = true
	data.Notification.Style.IsVibrate = true
	data.Notification.Style.IsFloat = true
	data.Notification.Style.IsClearable = true
	data.Notification.TransmissionContent = payload
	data.Notification.TransmissionType = true
	data.Cid = cid
	data.Requestid = fmt.Sprintf("%d%s", time.Now().UnixNano()/1000, utils.RandomStr(4))
	return PushSingle(data)
}
